#!/usr/bin/env python3
# -*- coding: utf-8 -*-
'''
Created on 2022-04-01 13:47:37
@author: DengLibin 榆霖
@description: 朴素贝叶斯 判定文档是否具有侮辱性
'''
import numpy as np


def load_data_set():
    """
    加载训练数据
    """
    # 文档 6行
    posting_list=[['my', 'dog', 'has', 'flea', 'problems', 'help', 'please'],
                 ['maybe', 'not', 'take', 'him', 'to', 'dog', 'park', 'stupid'],
                 ['my', 'dalmation', 'is', 'so', 'cute', 'I', 'love', 'him'],
                 ['stop', 'posting', 'stupid', 'worthless', 'garbage'],
                 ['mr', 'licks', 'ate', 'my', 'steak', 'how', 'to', 'stop', 'him'],
                 ['quit', 'buying', 'worthless', 'dog', 'food', 'stupid']]
    # 每行文档的类别 1 有侮辱行词汇, 0 没有
    class_vec = [0,1,0,1,0,1]
    return posting_list, class_vec

def create_vocab_list(data_set):
    """提取单词（去重）

    Args:
        data_set (_type_): _description_

    Returns:
        _type_: _description_
    """
    vocab_vec = set([])
    for document in data_set:
        # 求并集
        vocab_vec = vocab_vec | set(document)
    return list(vocab_vec)

def set_of_wordss2vec(vocab_list, input_set):
    """
    单词列表转向量
    标记input_set中的单词是否存在于vocal_list中，存在则标为1,不存在则标为0

    Args:
        vocab_list (_type_): 词汇表 如:['my', 'name', 'hello', 'world', 'work' ]
        input_set (_type_): 单词向量 如: ['my, 'hello']

    Returns:
        _type_: 结果向量 与 vocal_list长度相同（元素为1:存在，0：不存在）如：[1, 0, 1, 0, 0] (第一个1表示'my'这个单词在input_set中有，第二个0表示'name'这个单词在input_set中没有)

    """
    # 创建一个元素都为0的向量，长度为vocab_list的长度
    return_vec = [0] * len(vocab_list)
    # 遍历输入集合中的单词
    for word in input_set:
        # 单词在vocab_list集合中
        if word in vocab_list:
            # 相同位置为的值置为1
            return_vec[vocab_list.index(word)] = 1 
        else:
            print("单词:%s不在词汇表中" % word)
    return return_vec
 
def train_nb0(train_matrix, train_category):
    """朴素贝叶斯分类器训练函数

    Args:
        train_matrix (_type_): 训练矩阵多行，每一行的每个元素为0或1，为0表示当前位置对应的单词不存在，为1表示当前位置对应的单词存在
        train_categoroy (_type_): _description_
    """
    # 训练文档数量(行数)
    num_train_docs = len(train_matrix)
    # 文档单词数量（列数）
    num_words = len(train_matrix[0])
    # train_category 为1 的概率
    p_absuive = np.sum(train_category)/num_train_docs
    p0_num = np.zeros(num_words)
    p1_num = np.zeros(num_words)
    p0_denom = 0.0
    p1_denom = 0.0
    for i in range(num_train_docs):
        # 当前行的类别是1
        if train_category[i] == 1:
            # 类别1加上当前行
            p1_num +=train_matrix[i]
            # 类别1词条总数
            p1_denom += np.sum(train_matrix[i])
        else:
            # 类别0加上当前行
            p0_num += train_matrix[i]
            # 类别0词条总数
            p0_denom += sum(train_matrix[i])
    # 每个词属于类别1的概率
    p1_vect = p1_num/p1_denom
    # 每个词属于类别0的概率
    p0_vect = p0_num/p0_denom
    return p0_vect, p1_vect, p_absuive
    

def create_train_matrix(data_set):
    """构建训练矩阵 行数就是文档数，列数为所有文档中提取的单词去重后的单词数量

    Args:
        data_set (_type_): _description_
    """
    # 提取单词 得到词汇表(一个list)
    vocab_list = create_vocab_list(data_set)
    train_mat = []
    for line in data_set:
        train_mat.append(set_of_wordss2vec(vocab_list, line))
    return train_mat
  
  
def classify_nb(vec2clsssify, p0_vec, p1_vec, p_class1):
    """朴素贝叶斯分类

    Args:
        vec2clsssify (_type_): 输入文档词汇向量
        p0_vec (_type_): 类别0词汇概率向量
        p1_vec (_type_): 类别1词汇概率向量
        p_class1 (_type_): 类别1文档概率

    Returns:
        _type_: _description_
    """
    p1 = np.sum(vec2clsssify * p1_vec) + np.log(p_class1)
    p0 = np.sum(vec2clsssify * p0_vec) + np.log(1.0 - p_class1)
    if p1 > p0:
        return 1
    return 0
    
if __name__ == '__main__':
    data_set, class_vec = load_data_set()
    # 得到词汇表
    vocab_list = create_vocab_list(data_set)
    print(vocab_list)
    p0_v, p1_v, p_ab = train_nb0(create_train_matrix(data_set), class_vec)
   
    test_entry = ['love', 'my', 'dalmation']
    this_doc = np.array(set_of_wordss2vec(vocab_list, test_entry))
    print("分类结果：", classify_nb(this_doc, p0_v, p1_v, p_ab)) # 0 无侮辱性
    
    test_entry = ['stupid', 'garbage']
    this_doc = np.array(set_of_wordss2vec(vocab_list, test_entry))
    print("分类结果：", classify_nb(this_doc, p0_v, p1_v, p_ab)) # 1 有侮辱性
    
    
